﻿// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

#region

using Serilog;
using Serilog.Events;

#endregion

namespace Neto.Logging;

/// <summary>
///     Serilog配置选项
/// </summary>
public class SerilogConfigOptions : IConfigurableOptionsListener<SerilogConfigOptions>
{
    /// <summary>
    ///     控制台
    /// </summary>
    public SerilogConsole? Console { get; set; }

    /// <summary>
    ///     文件日志
    /// </summary>
    public SerilogFile? File { get; set; }

    /// <summary>
    ///     SqlServer日志
    /// </summary>
    public SerilogSQlServer? SqlServer { get; set; }

    /// <summary>
    ///     PostgreSQL日志
    /// </summary>
    public SerilogPostgreSQL? PostgreSQL { get; set; }

    public void OnListener(SerilogConfigOptions options, IConfiguration configuration)
    {
        var entityType = GetType(); //获得该类的Type

        var dics = options.GetDictionary();
        foreach (var item in dics)
        {
            var propertyInfo = entityType.GetProperty(item.Key);
            if (propertyInfo != null) propertyInfo.FieldSetValue(item.Key, item.Value);
        }
    }

    /// <summary>
    /// </summary>
    /// <param name="configOptions"></param>
    /// <param name="configuration"></param>
    public void PostConfigure(SerilogConfigOptions configOptions, IConfiguration configuration)
    {
        configOptions.Console ??= new SerilogConsole();
        configOptions.File ??= new SerilogFile();
        if (configOptions.SqlServer != null)
            if (string.IsNullOrWhiteSpace(configOptions.SqlServer.SchemaName))
                configOptions.SqlServer.SchemaName = "dbo";
    }
}

/// <summary>
///     定义了Serilog控制台日志的配置选项。
/// </summary>
public class SerilogConsole
{
    /// <summary>
    ///     是否同时将日志输出到控制台
    /// </summary>
    public bool IsEnable { get; set; } = false;

    /// <summary>
    ///     指定日志输出的模板。
    /// </summary>
    public string OutputTemplate { get; set; }
}

/// <summary>
///     定义了Serilog文件日志的配置选项。
/// </summary>
public class SerilogFile
{
    /// <summary>
    ///     是否启用文件日志记录。
    /// </summary>
    public bool IsEnable { get; set; } = true;

    /// <summary>
    ///     是否启用自定义删除日志
    /// </summary>
    public bool IsCustomerDeletedLog { get; set; }

    /// <summary>
    ///     是否根据日期创建日志文件夹
    /// </summary>
    public bool IsCreateDateFileFloder { get; set; } = true;

    // /// <summary>
    // /// 是否根据日志事件级别创建不同的文件夹。
    // /// </summary>
    // public bool IsLogEventLevelFloder { get; set; } = true;

    /// <summary>
    ///     文件大小达到限制时是否滚动日志文件。
    /// </summary>
    public bool RollOnFileSizeLimit { get; set; } = true;

    /// <summary>
    ///     指定最小的日志事件级别。
    /// </summary>
    public LogEventLevel MinLogEventLevel { get; set; } = LogEventLevel.Debug;

    /// <summary>
    ///     指定日志文件滚动的时间间隔。
    /// </summary>
    public RollingInterval RollingInterval { get; set; } = RollingInterval.Day;

    /// <summary>
    ///     限制保留的日志文件数量。
    ///     如果为true，则在达到文件大小限制时将创建一个新文件。文件名将以_NNN格式附加一个数字，第一个文件名没有数字。
    /// </summary>
    public int? RetainedFileCountLimit { get; set; }

    /// <summary>
    ///     允许保留的日志文件夹数量。
    /// </summary>
    public int? RetainedFloderCountLimit { get; set; }

    /// <summary>
    ///     指定将日志数据刷新到磁盘的间隔。
    ///     例如：= "00:05:00"; // 代表5分钟的间隔
    /// </summary>
    public TimeSpan? FlushToDiskInterval { get; set; }

    /// <summary>
    ///     是否启用缓冲以提高性能。
    /// </summary>
    public bool Buffered { get; set; } = false;

    /// <summary>
    ///     是否在多个实例间共享日志文件。
    /// </summary>
    public bool Shared { get; set; } = false;

    /// <summary>
    ///     文件日志的大小限制
    ///     文件大小限制字节：允许日志文件访问的近似最大大小（以字节为单位）成长。对于不受限制的增长，传递null。默认值为1 GB。避免写作部分事件，限制内的最后一个事件将全部写入偶数如果超过限制
    /// </summary>
    public long? FileSizeLimitBytes { get; set; } = 1073741824L;

    /// <summary>
    ///     指定日志输出的模板。
    /// </summary>
    public string OutputTemplate { get; set; } = SerilogX.SerilogOutputTemplate;
}

/// <summary>
///     定义了Serilog SQL Server日志的配置选项。
/// </summary>
public class SerilogSQlServer
{
    /// <summary>
    ///     是否启用SQL Server日志记录。
    /// </summary>
    public bool IsEnable { get; set; }

    /// <summary>
    ///     SQL Server的连接字符串。
    /// </summary>
    public string ConnectionString { get; set; }

    /// <summary>
    ///     存储日志的表名。
    /// </summary>
    public string TableName { get; set; } = "NetoLogs";

    /// <summary>
    ///     限制记录到日志表的最低日志级别
    /// </summary>
    public LogEventLevel RestrictedToMinimumLevel { get; set; } = LogEventLevel.Verbose;

    /// <summary>
    ///     限制每个批量多少日志事件写入数据库（默认值：50）
    /// </summary>
    public int BatchPostingLimit { get; set; } = 50;

    /// <summary>
    ///     控制日志事件发送到数据库的频率
    /// </summary>
    public string Period { get; set; } = "00:00:05";

    /// <summary>
    ///     是否自动创建日志表
    /// </summary>
    public bool AutoCreateSqlTable { get; set; } = true;

    /// <summary>
    ///     数据库名称,默认dbo,不建议修改
    /// </summary>
    public string SchemaName { get; set; } = "dbo";

    /// <summary>
    ///     是否需要自动创建数据库
    /// </summary>
    public bool AutoCreateSqlDatabase { get; set; } = true;
}

/// <summary>
///     定义了Serilog PostgreSQL日志的配置选项。
/// </summary>
public class SerilogPostgreSQL
{
    /// <summary>
    ///     是否启用PostgreSQL日志记录。
    /// </summary>
    public bool IsEnable { get; set; }

    /// <summary>
    ///     PostgreSQL的连接字符串。
    /// </summary>
    public string ConnectionString { get; set; }

    /// <summary>
    ///     存储日志的表名
    /// </summary>
    public string TableName { get; set; } = "NetoLogs";

    /// <summary>
    ///     是否需要自动创建数据库
    /// </summary>
    public bool NeedAutoCreateSchema { get; set; } = true;

    /// <summary>
    ///     数据库名称
    /// </summary>
    public string SchemaName { get; set; }

    /// <summary>
    ///     是否需要自动创建日志表
    /// </summary>
    public bool NeedAutoCreateTable { get; set; } = true;

    /// <summary>
    ///     限制记录到日志表的最低日志级别
    /// </summary>
    public LogEventLevel RestrictedToMinimumLevel { get; set; } = LogEventLevel.Debug;

    /// <summary>
    ///     限制每个批量多少日志事件写入数据库（默认值：50）
    /// </summary>
    public int BatchPostingLimit { get; set; } = 50;

    /// <summary>
    ///     控制日志事件发送到数据库的频率
    /// </summary>
    public string Period { get; set; } = "00:00:05";
}